type Fn = (...arg: any[]) => any
type Item<T> = [Fn, Fn, Promise2<T>]
type State = 'pending' | 'success' | 'fail'
/**
 * 运行机制
 * nextPromise = then(onResolve, onReject)
 * --------- 基本 ---------
 * 当resolve时, 执行onResolve列
 * 当reject时, 执行onReject列
 * --------- 透传 ---------
 * 当resolve时, onResolve不存在, nextPromise.resolve()
 * 当reject时, onReject不存在, nextPromise.reject()
 * --------- 处理回调返回值 ---------
 * 当onResolve、onReject返回非Promise对象, nextPromise.resolve()
 * 当onResolve、onReject返回Promise.resolve(), nextPromise.resolve()
 * 当onResolve、onReject返回Promise.reject(), nextPromise.reject()
 * [
 *   [onResolve, onReject, nextPromise]
 *   [onResolve, onReject, nextPromise]
 *   [onResolve, onReject, nextPromise]
 *   [onResolve, onReject, nextPromise]
 *   [onResolve, onReject, nextPromise]
 *   [onResolve, onReject, nextPromise]
 * ]
 */
export default class Promise2<T> {
  private state: State = 'pending'
  private queue: Item<T>[] = []
  private res: T  // Promise.resolve(res).then(res => console.log(res))
  private err: any  // Promise.reject(err).catch(err => console.log(res))

  constructor(cb: Fn) {
    cb.call(
      undefined,
      this.resolve.bind(this),
      this.reject.bind(this)
    )
  }

  resolve(data?: T) {
    if (this.state !== 'pending') return // 多次执行resolve, 只有第一次才生效
    this.state = 'success'
    this.res = data
    this.dispatch()
  }

  reject(err?: any) {
    if (this.state !== 'pending') return // 多次执行reject, 只有第一次才生效
    this.state = 'fail'
    this.err = err
    this.dispatch()
  }
  /**
   * setTimeout确保then方法将回调放入queue中后再开始遍历
   */
  dispatch() {
    const timer = setTimeout(() => {
      this.queue.forEach(item => this.processingItem(item))
      clearTimeout(timer)
    })
  }
  /**
   * 回调函数存在: 根据回调返回值触发nextPromise
   * 回调函数不存在: 根据this.state触发nextPromise
   */
  processingItem(item: Item<T>) {
    const [onResolve, onReject, nextPromise] = item
    const cb = this.state === 'success' ? onResolve : onReject
    const data = this.state === 'success' ? this.res : this.err
    if (cb) {
      const res = cb(data)
      this.processingReturn(res, nextPromise)
    } else {
      if (this.state === 'success') nextPromise.resolve(data)
      if (this.state === 'fail') nextPromise.reject(data)
    }
  }
  /**
   * 如果返回的是promise对象: nextPromise resolve reject 取决于回调函数返回的promise对象
   * 如果返回的是非promise对象: nexPromise 就直接 resolve 该返回值
   */
  processingReturn(x: any, nextPromise: Promise2<T>) {
    if (x instanceof Promise2) {
      x.then(
        res => nextPromise.resolve(res),
        err => nextPromise.reject(err)
      )
    } else {
      nextPromise.resolve(x)
    }
  }

  then(onResolve?: Fn, onReject?: Fn) {
    const promise = new Promise2<T>(()=>{})
    this.queue.push([onResolve, onReject, promise])
    return promise
  }

  catch(onReject?: Fn) {
    return this.then(null, onReject)
  }

  static resolve(data?: any) {
    return new Promise2(s=>s(data))
  }

  static reject(data?: any) {
    return new Promise2((_,j)=> j(data))
  }
  /**
   * 多次resolve, 只有第一次才生效
   * 谁先resolve, 就用谁的数据
   */
  static race(arr: Promise2<any>[]) {
    return new Promise2((resolve, reject) => {
      arr.forEach(promise => {
        promise.then(
          res => resolve(res),
          err => reject(err)
        )
      })
    })
  }

  static all(arr: Promise2<any>[]) {
    return new Promise2((resolve, reject) => {
      let resList = []
      const onReject = (res: any) => {
        resList.push(res)
        if(resList.length === arr.length) resolve(resList)
      }

      arr.forEach(promise => {
        promise.then(onReject)
        .catch(err => reject(err))
      })
    })
  }
}